;-----------------------------------------
;       PicOS Project
;
;       HEPIA 2014 - Florent Gluck
;
;       Denis Voirol            Pierre Kiss
;       Ruben Magnin            Alina Stanculescu
;       Sebastien Beureux       Julien Cornut
;-----------------------------------------
;
;       jump_asm.s
;
;       Jump and start executing code at specified segment
;
;-----------------------------------------

.global _jump
STACK_OFFS equ 0xfbfe	; offset at which the stack starts

;------------------------------------------------------------------------------
; Jump and start executing code at the specified segment.
; void jump(uint segment)

_jump:
	push bp
	mov bp,sp
	mov bx,[bp+4] ; get the segment to jump to into bx

	push ds ; save ds as it will be modified below

	push si
	mov ax,cs ; modify the jmp below to jump to the specified segment
	mov ds,ax
	mov si,#jump
	mov [si+3],bx ; change the first 0000 to the segment
	pop si

	pop ax ; save segment of the caller in ax (= ds which was pushed above)
	mov cx,sp ; save stack pointer
	mov dx,bp ; save base pointer

	mov ds,bx ; set up the segment registers to the specified segment
	mov ss,bx
	mov es,bx

	mov sp,#STACK_OFFS ; set up the stack pointer
	mov bp,#STACK_OFFS
	
	; push sp, bp and current segment in order to resume
	; the execution context when returning from the call
	push cx; sp
	push dx; bp
	push ax; ds
	
	; far call (push both cs and ip on the stack)
jump:	call #0x0000:0x0000 ; start running (the first 0000 is changed above)
	
	; restore ds, bp and sp into ax, bx and cx
	pop ax ; ds
	pop bx ; bp
	pop cx ; sp

	; restore the caller's context (segments, bp and sp)
	mov ds,ax
	mov es,ax
	mov ss,ax
	mov bp,bx
	mov sp,cx

	pop bp
	ret
